﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Chaunce.FrameWork.NetCore.EasyRedis
{
    /// <summary>
    /// Represents a manager for caching in Redis store (http://redis.io/).
    /// Mostly it'll be used when running in a web farm or Azure. But of course it can be also used on any server or environment
    /// </summary>
    public partial class RedisCacheManager : ICacheManager
    {
        #region Fields

        private readonly IRedisCache _redisCache;

        #endregion

        #region Ctor

        /// <summary>
        /// Ctor
        /// </summary>
        /// <param name="redisCache">Cache manager</param>
        public RedisCacheManager(IRedisCache redisCache)
        {
            this._redisCache = redisCache;
        }

        #endregion

        #region Methods

        /// <summary>
        ///获取缓存 异步
        /// </summary>
        /// <typeparam name="T">缓存值类型 json反序列化</typeparam>
        /// <param name="key">Key of cached item</param>
        /// <returns>The cached value associated with the specified key</returns>
        public async Task<T> GetAsync<T>(string key) where T : class
        {
            var item = await _redisCache.GetAsync<T>(key);
            return item;
        }

        /// <summary>
        /// 新增缓存
        /// </summary>
        /// <param name="key">缓存key值,key值必须满足规则：模块名:类名:业务方法名:参数.不满足规则将不会被缓存</param>
        /// <param name="data">缓存值 可以序列化的值</param>
        /// <param name="cacheTime">缓存有效期 分钟</param>
        public async Task<bool> SetAsync(string key, object data, int cacheTime)
        {
            //缓存key值到set集合中，目的为了在清除缓存时能够直接找到在模块业务下面所有的key值.例如:key等于marketing:platform:getallplatformlist,那么其父key就是marketing:platform
            string parentKey = string.Empty;
            var arr = key.Split(':');
            if (arr.Length > 2)
            {
                parentKey = string.Join(":", arr.Take(2));
            }
            if (string.IsNullOrWhiteSpace(parentKey))
            {
                return false;
            }

            var ret = await _redisCache.SetAsync(key, data, TimeSpan.FromMinutes(cacheTime));
            if (ret)
            {
                _redisCache.SortedSetAdd(parentKey, key, 1);
            }
            return ret;
        }

        /// <summary>
        ///删除缓存 根据key 匹配值
        /// </summary>
        /// <param name="pattern">key 匹配值</param>
        public async Task RemoveByPatternAsync(string pattern)
        {
            await _redisCache.DeleteByPatternAsync(pattern);
        }


        /// <summary>
        ///获取缓存
        /// </summary>
        /// <typeparam name="T">Type of cached item</typeparam>
        /// <param name="key">Key of cached item</param>
        /// <returns>The cached value associated with the specified key</returns>
        public T Get<T>(string key) where T : class
        {
            return _redisCache.Get<T>(key);
        }

        /// <summary>
        ///新增缓存
        /// </summary>
        /// <param name="key">缓存key值,key值必须满足规则：模块名:类名:业务方法名:参数.不满足规则将不会被缓存</param>
        /// <param name="data">Value for caching</param>
        /// <param name="cacheTime">Cache time in minutes</param>
        public bool Set(string key, object data, int cacheTime)
        {
            //缓存key值到set集合中，目的为了在清除缓存时能够直接找到在模块业务下面所有的key值.例如:key等于marketing:platform:getallplatformlist,那么其父key就是marketing:platform
            string parentKey = string.Empty;
            var arr = key.Split(':');
            if (arr.Length > 2)
            {
                parentKey = string.Join(":", arr.Take(2));
            }
            if (string.IsNullOrWhiteSpace(parentKey)) return false;
            var ret = _redisCache.Set(key, data, TimeSpan.FromMinutes(cacheTime));
            if (ret)
            {
                _redisCache.SortedSetAdd(parentKey, key, 1);
            }
            return ret;
        }

        /// <summary>
        /// 缓存是否存在
        /// </summary>
        /// <param name="key">Key of cached item</param>
        /// <returns>True if item already is in cache; otherwise false</returns>
        public virtual bool IsSet(string key)
        {
            return _redisCache.KeyExists(key);
        }

        /// <summary>
        /// 删除缓存
        /// </summary>
        /// <param name="key">Key of cached item</param>
        public void Remove(string key)
        {
            _redisCache.KeyDelete(key);
        }

        /// <summary>
        /// 删除缓存 根据key 匹配值
        /// </summary>
        /// <param name="pattern">String key pattern</param>
        public void RemoveByPattern(string pattern)
        {
            _redisCache.DeleteByPattern(pattern);
        }

        /// <summary>
        /// 删除缓存根据 parentKey.parentKey规则一般取子keys的前面两部分,是自动的.
        /// </summary>
        /// <param name="key"></param>
        public void RemoveByParentKey(string key)
        {
            var childKeys = _redisCache.SortedSetRangeByRank<string>(key);
            childKeys.ForEach(r =>
            {
                this.Remove(r);
            });
        }
        #endregion
    }
}
